package com.ding.easycontroller.service.impl;

import com.ding.easycontroller.dao.FilterDao;
import com.ding.easycontroller.exception.CheckException;
import com.ding.easycontroller.service.FilterService;
import com.ding.easycontroller.utils.IdStrategy;
import com.ding.easycontroller.work.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.ScriptEngine;
import java.util.ArrayList;
import java.util.List;

@Service
public class FilterServiceImpl implements FilterService {


    private List<Filter> beforeFilters = new ArrayList<>();
    private List<Filter> defaultFilters = new ArrayList<>();
    private List<Filter> afterFilters = new ArrayList<>();
    private List<Filter> all = new ArrayList<>();

    @Autowired
    private FilterDao filterDao;


    @Autowired
    private ScriptEngine scriptEngine;

    @Override
    public List<Filter> getBeforeFilters() {
        return beforeFilters;
    }

    @Override
    public List<Filter> getAfterFilters() {
        return afterFilters;
    }

    @Override
    public List<Filter> getDefaultFilters() {
        return defaultFilters;
    }

    private void initFilter(Filter filter) {
        filter.setScriptEngine(scriptEngine);
        try {
            filter.init();
        } catch (Exception e) {
            throw new CheckException(e);
        }
    }

    private void tryAdd(Filter filter) {
        if (filter.getId() == null) {
            filter.setId(IdStrategy.createId(filter));
        }
        initFilter(filter);
        sortAndAdd(filter);
    }

    private void sortAndAdd(Filter filter) {
        int order = filter.getOrder();
        if (filter.getBeforeFunctionName() != null) {
            int i = 0;
            for (; i < beforeFilters.size(); i++) {
                if (beforeFilters.get(i).getOrder() > order) {
                    break;
                }
            }
            beforeFilters.add(i, filter);
        }
        if (filter.getDefaultFunctionName() != null) {
            int i = 0;
            for (; i < defaultFilters.size(); i++) {
                if (defaultFilters.get(i).getOrder() > order) {
                    break;
                }
            }
            defaultFilters.add(i, filter);
        }
        if (filter.getAfterFunctionName() != null) {
            int i = 0;
            for (; i < afterFilters.size(); i++) {
                if (afterFilters.get(i).getOrder() <= order) {
                    break;
                }
            }
            afterFilters.add(i, filter);
        }
        int i = 0;
        for (; i < all.size(); i++) {
            if (all.get(i).getOrder() > order) {
                break;
            }
        }
        all.add(i, filter);
    }

    @Override
    public void removeById(String id) {
        Filter filter = getById(id);
        if (filter == null) {
            return;
        }
        filter.destroy();
        all.remove(filter);
        afterFilters.remove(filter);
        beforeFilters.remove(filter);
        defaultFilters.remove(filter);
        filterDao.removeById(id);
    }

    private Filter getById(String id) {
        for (Filter filter : all) {
            if (id.equals(filter.getId())) {
                return filter;
            }
        }
        return null;
    }

    @Override
    public void updateOrAdd(Filter filter) {
        if (filter.getId() != null) {
            Filter f = getById(filter.getId());
            if (f == null) {
                throw new RuntimeException("不存在的filter:" + filter.getId());
            }
            tryUpdate(filter, f);
            filterDao.update(filter);
        } else {
            tryAdd(filter);
            filterDao.add(filter);
        }
    }

    private void tryUpdate(Filter filter, Filter old) {
        old.destroy();
        removeById(old.getId());
        try {
            filter.setId(old.getId());
            tryAdd(filter);
        } catch (Exception e) {
            old.init();
            tryAdd(old);
            e.printStackTrace();
        }
    }

    @Override
    public void init() {

        List<Filter> allAfterFilters = filterDao.listAll();
        for (Filter filter : allAfterFilters) {
            try {
                tryAdd(filter);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Filter get(String id) {
        return getById(id);
    }

    @Override
    public List<Filter> getAll() {
        return all;
    }

}
